/*******************************************************************************
 *  Manik Hot Deploy
 *  Copyright (C) 2010 Ralph Soika  
 *  http://www.imixs.com
 *  
 *  This program is free software; you can redistribute it and/or 
 *  modify it under the terms of the GNU General Public License 
 *  as published by the Free Software Foundation; either version 2 
 *  of the License, or (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 *  General Public License for more details.
 *  
 *  You can receive a copy of the GNU General Public
 *  License at http://www.gnu.org/licenses/gpl.html
 *  
 *  Contributors:  
 *  	Ralph Soika 
 * 
 *******************************************************************************/
package org.imixs.eclipse.manik;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.QualifiedName;

/**
 * The Builder Class for hot deployment resource files
 * @author rsoika
 *
 */
public class HotdeployBuilder extends IncrementalProjectBuilder {

	public static final String BUILDER_ID = "org.imixs.eclipse.manik.hotdeployBuilder";

	private String[] skipFolderList = { "/src/main/resources/",
			"/src/main/java/", "/src/test/resources/", "/src/test/java/" };

	private String[] skipSourcePathList = { "/classes/", "/src/main/webapp/" };

	private String filter = "EAR";
	private String target = "";
	private String sourceFilePath = "";
	private String sourceFileName = "";

	
	@SuppressWarnings("unchecked")
	@Override
	protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
			throws CoreException {
		if (kind == FULL_BUILD) {
			// fullBuild(monitor);
			System.out.println("HotdeployBuilder - FULL_BUILD not supported");
		} else {
			IResourceDelta delta = getDelta(getProject());
			if (delta == null) {
				// fullBuild(monitor);
				System.out.println("HotdeployBuilder - MODE not supported");
			} else {
				incrementalBuild(delta, monitor);
			}
		}
		return null;
	}

	protected void incrementalBuild(IResourceDelta delta,
			IProgressMonitor monitor) throws CoreException {
		// the visitor does the work.
		delta.accept(new HotdeployDeltaVisitor());
	}

	/**
	 * copies the resource into the target server
	 * 
	 * the target of the file to be copied is computed by the helper method
	 * computeTarget()
	 * 
	 * 
	 * @param resource
	 *            The SourceFile
	 * 
	 * @param bremove
	 *            indicates if the Sourcefile should be removed or added
	 * 
	 * @throws CoreException
	 */
	void deployResource(IResource resource, boolean bremove)
			throws CoreException {

		target = this.getProject().getPersistentProperty(
				new QualifiedName("", TargetPropertyPage.TARGET_PROPERTY));
		if (!target.endsWith("/"))
			target += "/";

		filter = this.getProject().getPersistentProperty(
				new QualifiedName("", TargetPropertyPage.FILTER_PROPERTY));

		if (resource instanceof IFile) {
			IFile file = (IFile) resource;

			sourceFileName = file.getName();
			sourceFilePath = file.getFullPath().toString();

			// skipp files like .java
			for (String value : skipFolderList) {
				if (sourceFilePath.contains(value)) {
					return;
				}
			}

			// check for current filter setting
			// skip if EAR or WAR and invalid sourcefile type....
			if (("EAR".equals(filter) && !sourceFileName.endsWith(".ear"))
					|| ("WAR".equals(filter) && !sourceFileName
							.endsWith(".war")))
				return;

			// source file ok - so now compute the target path....
			String targetFilePath = computeTarget();

			try {
				if (bremove) {
					// remove file
					File f = new File(targetFilePath);
					f.delete();
				} else {
					// Copy the file....
					// System.out.println("copy file: " + sourceFilePath);
					InputStream is = file.getContents();
					File fOutput = new File(targetFilePath);
					OutputStream out = new FileOutputStream(fOutput);
					byte buf[] = new byte[1024];
					int len;
					while ((len = is.read(buf)) > 0)
						out.write(buf, 0, len);
					out.close();
					is.close();
				}
			} catch (Exception e) {

				e.printStackTrace();
			}

		}
	}

	/**
	 * This method dose the magic of the manik hot deployer. The method computes
	 * the target goal inside an application target. There are three different
	 * cases:
	 * 
	 * case-1): .war or .ear files are simply deployed into the target root. No
	 * hierarchy is computed
	 * 
	 * case-2): the target is a web application. This is indicated by the
	 * existence of an /WEB-INF folder. in this case we check for two different
	 * source files
	 * 
	 * case-2-a): the source file contains the path /target/classes/ - so we
	 * copy the source into [target]/WEB-INF/classes
	 * 
	 * case-2-b): otherwise we copy into the target root strip any
	 * /target/main/webcontent präfixes
	 * 
	 * 
	 * case-3): the target is no web application. So we can copy the source into
	 * the target root stripp any /target/main/src präfixes
	 * 
	 * 
	 * 
	 * 
	 * 
	 * @param resource
	 * @throws CoreException
	 */
	private String computeTarget() {
		File folder =null;

		/* case-1 */

		// check for current filter setting
		// if EAR or WAR simply deploy into target folder
		if (("EAR".equals(filter) && sourceFileName.endsWith(".ear"))
				|| ("WAR".equals(filter) && sourceFileName.endsWith(".war")))
			return target + sourceFileName;

		/* case-2 case a and b included */
		// test if the sourcefile contains a source path which needs to be
		// removed ?
		for (String value : skipSourcePathList) {
			if (sourceFilePath.contains(value)) {

				String path = sourceFilePath.substring(sourceFilePath
						.indexOf(value)
						+ value.length() - 0);

				// now test if the target folder is a web application and the
				// sourcfile is a /classes/ file
				// - test for /WEB-INF/ folder
				if (sourceFilePath.contains("/classes/")) {
					folder = new File(target + "/WEB-INF/");
					if (folder.exists()) {
						// target is web app - so we need to extend the target....
						path = "/WEB-INF/classes/" + path;
					}
				}

				// test target folder - if not exists create path...
				if (path.indexOf('/') > -1) {
					folder = new File(target
							+ path.substring(0, path
									.lastIndexOf('/')));
					if (!folder.exists())
						folder.mkdirs();
				}
				
				
				return target + path;

			}
		}

		return target + sourceFilePath;

	}

	class HotdeployDeltaVisitor implements IResourceDeltaVisitor {
		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse
		 * .core.resources.IResourceDelta)
		 */
		public boolean visit(IResourceDelta delta) throws CoreException {
			IResource resource = delta.getResource();
			switch (delta.getKind()) {
			case IResourceDelta.ADDED:
				// handle added resource
				deployResource(resource, false);
				break;
			case IResourceDelta.REMOVED:
				// handle removed resource
				deployResource(resource, true);
				break;
			case IResourceDelta.CHANGED:
				// handle changed resource
				deployResource(resource, false);
				break;
			}
			// return true to continue visiting children.
			return true;
		}
	}

}
